Import mojo
Import yimDebug
Import yimMath
Import yimCommon
Import yimInput
Import yimTimer
Import yimTiles
Import yimCollision
Import yimSprites
Import yimPaths
Import yimParticles
Import yimSound
Import yimJuicies

Import yimBox2DEmpty
'Import yimBox2D

Global yimDeltaLast:Float
Global yimDeltaMills:Float
Global yE:yimEngine

Function yimDelta:Float(val:Float)

	Return val
	
	Return val * ((Millisecs()-yimDeltaLast)/yimDeltaMills)
	
End

Function yimDeltaSetFPS(fps:Float)
	yimDeltaMills = 1000.0/fps
End

#REM
	summary: yimWork is a monster that depends on yimStates to survive.
	
	When you create your game state, you must Extend yimState, like so:
	
	Class gameState Extends yimState
	
		Method OnCreate()
			
		End
		
		Method OnUpdate()
			
		End
		
		Method OnRender()
			
		End
		
	End
	
	You can create multiple yimStates for different menus and stages
	in your game and pause, reset, and switch between them on the fly!
	
#END
Class yimState
	Field sprWorld:yimSpriteWorld = Null
	Field bgColor:yimColor = New yimColor(0, 0, 0, 255)

	Field milliOffset:Int = 0
	Field milliLast:Int = 0
	
	Field paused:Bool = False
	
	'summary: This method is called whenever the yimState it belongs to is added to the yimEngine or reset
	Method OnCreate()
	
	End
	
	'summary: This is only called if the yimState it belongs to is the current state. Otherwise it is paused.
	Method OnUpdate()
		
	End
	
	'summary: This is called if it belongs to the current yimState AND is paused. Allows for wicked cool pause screens.
	Method OnPausedUpdate()
		
	End
	
	'summary: This is called if it belongs to the current yimState. Does not depend on whether the yimState is paused or not. It just is called.
	Method OnRender()
		
	End
	
	'summary: This is called if the mobile device suspends the app to switch to a different app and whatnot
	Method OnSuspend()
		
	End
	
	'summary: This is called when the mobile device resumes the app from suspension
	Method OnResume()
		
	End
	
	'summary: Sets the background of this yimState
	Method SetBackgroundColor(red:Int, green:Int, blue:Int)
		bgColor.Set(red, green, blue)
	End
	
	Method Milli:Int()
		Return Millisecs()-milliOffset
	End
	
	'summary: Resets the yimState. In other words, deletes any and all created objects and re-calls OnCreate()
	Method Reset()
		sprWorld.Reset()
		milliOffset = Millisecs()
		milliLast = Millisecs()
		OnCreate()
	End
	
	'summary: Pauses the yimState.
	Method Pause(pause:Bool=True)
		If pause
			paused = True
			StopTimer()
		Else
			Play()
		EndIf
	End
	
	Method StopTimer()
		milliLast = Millisecs()
	End
	
	Method StartTimer()
		milliOffset += Millisecs() - milliLast
	End
	
	'summary: Resumes the yimState.
	Method Play()
		StartTimer()
		paused = False
	End
End

#REM
	summary: The yimWork class. Quite the beast.
	
	To create the yimEngine object, you do this in your Main function:
	
	New yimEngine(states:yimState[], updateRate:Float=60, virtualWidth:Int = 640, virtualHeight:Int = 480, debugMode:Bool=False, fillExtraSpace:Bool = True)
	
	[b]states[/b] is an array of yimState objects that you create. For some reason, even though your game states extend yimState, you have to cast your game state references within the array, like so: [yimState(menu), yimState(game)]
	
	[b]updateRate[/b] is the rate at which the game updates per second.
	
	[b]virtualWidth, virtualHeight[/b] are your virtual resolution dimensions. This allows your game to look the same on ALL devices. So, if set to 640 x 480, a 640 x 480 image will fill the screen on every device.
	
	[b]debugMode[/b] determines whether or not to show debug information on the screen.
	
	[b]fillExtraSpace[/b], if set to true, will fill the edges of the screen with black, if the aspect ratio of the screen doesn't match that of your virtual resolution.

	[b]To enable physics[/b], you need to change:
	
	Import yimBox2DEmpty
	'Import yimBox2D
	
	to:
	
	'Import yimBox2DEmpty
	Import yimBox2D
	
	inside yimWork.monkey. Also you will need to install [a http://code.google.com/p/monkeybox2d/]http://code.google.com/p/monkeybox2d/[/a]


#END
Class yimEngine Extends App
	Field updates:Int = 0
	
	Field vWidth:Float
	Field vHeight:Float
	
	Field virtScale:yimVec2D = New yimVec2D(0.0, 0.0)
	Field origScale:yimVec2D = New yimVec2D(0.0, 0.0)
	Field device:yimVec2D
	Field halfDevice:yimVec2D
	Field fillEdges:Bool = True
	
	Field screenRect:yimRect
	
	Field curState:yimState
	Field states:yimState[]
	
	Field upRate:Float
	
	Field img:Image
	
	Field inputManager:yimputManager = Null
	
	Field fpsTicker:yimTicker = New yimTicker(1000)
	Field fps:Int = 0
	Field frames:Int = 0
	
	Field collGroups:List<yimCollGroup> = New List<yimCollGroup>()
	
	Field events:List<yimTicker> = New List<yimTicker>()
	
	Field paths:List<yimPath> = New List<yimPath>()
	Field dbgDrawPaths:Bool = True
	Field dbgDrawCollBodies:Bool = True
	Field dbgDrawCommands:Int = 0

	Field images:StringMap<Image> = New StringMap<Image>()
		
	Field edgeRects:yimRect[] = New yimRect[2]
	
	Method New(_states:yimState[], _updateRate:Float=60, virtualWidth:Int = 640, virtualHeight:Int = 480, debugMode:Bool=False, fillExtraSpace:Bool = True)
		upRate = _updateRate
		yimDeltaSetFPS(upRate)
		vWidth = virtualWidth
		vHeight = virtualHeight
		curState = _states[0]
		states = _states
		fillEdges = fillExtraSpace
		
		SetDebug(debugMode)
		yE = Self
		
	End
	
	'summary: Allows you to set the debug mode after yimEngine creation
	Method SetDebug(dbg:Bool=True)
		yim_debugMode = dbg
	End

	Method OnCreate()
	
		device = New yimVec2D(DeviceWidth(), DeviceHeight())
		halfDevice = New yimVec2D(device.x/2.0, device.y/2.0)
		
		screenRect = New yimRect(0, 0, device.x, device.y)	

		If (device.y/vHeight) > (device.x/vWidth)
			
			virtScale.x = device.x/vWidth
			virtScale.y = virtScale.x
			
			If fillEdges
				Local midHeight:Float = (device.y-vHeight)/2
				
				edgeRects[0] = New yimRect(halfDevice.x, midHeight/2, device.x, midHeight)
				edgeRects[1] = New yimRect(halfDevice.x, device.y - midHeight/2, device.x, midHeight)
			EndIf
			
		Else
			virtScale.y = device.y/vHeight
			virtScale.x = virtScale.y
			
			If (device.y/vHeight) < (device.x/vWidth) And fillEdges
				Local midWidth:Float = (device.x-vWidth)/2
				
				edgeRects[0] = New yimRect(midWidth/2, halfDevice.y, midWidth, device.y)
				edgeRects[1] = New yimRect(device.x-midWidth/2, halfDevice.y, (device.x-vWidth)/2, device.y)
			EndIf
		Endif
		
		origScale.Copy(virtScale)
		
		SetUpdateRate(upRate)
		

		fpsTicker.Start()
		
		For Local state:= EachIn states
			curState = state
			InitState(state)
		Next
		
		curState = states[0]
		
		yimDeltaLast = Millisecs()
	End
	
	Method OnUpdate()
		If inputManager <> Null
			inputManager.Update()
		Endif
			
		Local time:Float = Millisecs()
		
		If Not curState.paused
			curState.OnUpdate()
			curState.sprWorld.Update()
		Else
			curState.OnPausedUpdate()
		EndIf
		
		For Local curEvent:yimTicker = EachIn events
			curEvent.Update()
		Next
		
		If inputManager <> Null
			inputManager.UpdateMouse()
		Endif
		
		yimDeltaLast = Millisecs()
		
		screenRect.SetPosition(curState.sprWorld.camPos.x*virtScale.x, -curState.sprWorld.camPos.y*virtScale.y)
		screenRect.SetAngle(curState.sprWorld.camAng)
		screenRect.Update()
		
		updates += 1
	End
	
	Method OnRender()
		updates = 0
		Cls(curState.bgColor.r, curState.bgColor.g, curState.bgColor.b)
		dbgDrawCommands = 0
		
		yim_SaveColorAndAlpha()
		
		
		PushMatrix()
		
		Translate(DeviceWidth()/2.0, DeviceHeight()/2.0)
		
		curState.sprWorld.Render()
		
		PopMatrix()
		
		yim_RestoreColorAndAlpha()
		
		#REM
		If inputManager <> Null
			If inputManager.onScreenList.Count() > 0
				inputManager.RenderOnScreenInputs()
			Endif
		Endif
		#END
		
		If dbgDrawPaths
			For Local tPath:= EachIn paths
				tPath.Draw(Self)
			Next
		EndIf
		
		If yim_debugMode
			Debug("FPS: "+fps)
			Debug("Sprite Count: "+curState.sprWorld.curLayer.sprList.Count())
			Local bodyCount:Int = 0
			For Local tGrp:= EachIn collGroups
				bodyCount += tGrp.bodyList.Count()
			Next
			If bodyCount > 0
				Debug("Body Count: "+bodyCount)
			EndIf
			
			If dbgDrawCommands > 0
				Debug("Sprite Draws: "+dbgDrawCommands)
			EndIf
			
			If curState.sprWorld.b2dWorld
				Debug("B2D Bodies: "+curState.sprWorld.b2dWorld.GetBodyCount())
				Debug("B2D Joints: "+curState.sprWorld.b2dWorld.GetJointCount())
			EndIf
			
			If curState.paused
				Debug("*** PAUSED ***")
			EndIf
			
			frames += 1
			If fpsTicker.Ticked()
				fps = frames
				frames = 0
			EndIf
		EndIf
		
		curState.OnRender()
		
		If edgeRects[0]
			yim_SaveColorAndAlpha()
			SetAlpha(1)
			SetColor(0,0,0)
			edgeRects[0].Draw(True)
			edgeRects[1].Draw(True)
			yim_RestoreColorAndAlpha()
		EndIf

		ShowDebug()
	End
	
	Method OnSuspend()
		curState.OnSuspend()
	End
	
	Method OnResume()
		curState.OnResume()
	End
	
	Method InitState(state:yimState)
		state.sprWorld = New yimSpriteWorld(Self, virtScale)
		state.OnCreate()
	End
	
	'summary: Add a yimState to the yimEngine on the fly!
	Method AddState:Int(state:yimState)
		states = states.Resize(states.Length+1)
		states[states.Length-1] = state
		Print(states.Length-1)
		Return states.Length-1
	End
	
	'summary: Switch states by yimState reference
	Method SwitchState(state:yimState)
		curState.StopTimer()
		curState = state
		If Not curState.sprWorld
			InitState(curState)
		End
		curState.StartTimer()
	End
	
	'summary: Switch states by index in the states array
	Method SwitchState(stateIndex:Int)
		 SwitchState(states[stateIndex])
	End
	
	'summary: Resets the provided state. Alternatively, Reset() can be called within your yimState object.
	Method ResetState(state:yimState)
		state.Reset()
	End
	
	'summary: Resets the provided state. Alternatively, Reset() can be called within your yimState object.
	Method ResetState(stateIndex:Int)
		 ResetState(states[stateIndex])
	End
	
	'summary: Sets the z-position or zoom level of the 2D camera. Is nice!
	Method ZoomCamera(zoom:Float)
		curState.sprWorld.ZoomCamera(zoom)
	End
	
	'summary: Sets the zoom level of the 2D camera to its default position, in case you get lost.
	Method ResetCameraZoom()
		curState.sprWorld.ResetCameraZoom()
	End
	
	'summary: Sets the angle of the camera.
	Method SetCameraAngle(ang:Float)
		curState.sprWorld.camAng = ang
	End
	
	'summary: Rotates the camera by the provided amount.
	Method RotateCamera(ang:Float)
		curState.sprWorld.camAng += ang
	End
	
	'summary: Sets the position of the camera in map coordinates. Not screen coordinates. (0, 0) sets the camera to the middle of the map.
	Method SetCameraPosition(cX:Float, cY:Float)
		curState.sprWorld.camPos.x = cX
		curState.sprWorld.camPos.y = cY
	End
	
	'summary: Moves the camera in the x and y directions. Optional relative flag.
	Method MoveCamera(x:Float, y:Float, relative:Bool=False)
		If Not relative
			SetCameraPosition(curState.sprWorld.camPos.x + x, curState.sprWorld.camPos.y + y)
		Else
			SetCameraPosition(curState.sprWorld.camPos.x + Cos(curState.sprWorld.camAng)*x + Sin(curState.sprWorld.camAng)*y, curState.sprWorld.camPos.y - Sin(curState.sprWorld.camAng)*x + Cos(curState.sprWorld.camAng)*y)
		EndIf
	End
	
	'summary: Sets the current sprite layer to perform sprite removal and addition on.
	Method SetCurrentLayer(layer:yimSpriteLayer)
		curState.sprWorld.SetCurLayer(layer)
	End
	
	'summary: Gets the yimSpriteLayer reference of the current sprite layer
	Method GetCurrentLayer:yimSpriteLayer()
		Return curState.sprWorld.curLayer
	End
	
	'summary: Sets the current sprite layer to perform sprite removal and addition on by name.
	Method SetCurrentLayerByName(name:String)
		curState.sprWorld.SetCurLayer(sprWorld.GetLayerByName(name))
	End
	
	'summary: Gets the yimSpriteLayer reference of the a sprite layer by name.
	Method GetLayer:yimSpriteLayer(name:String)
		Return curState.sprWorld.GetLayerByName(name)
	End
	
	'summary: Creates a new sprite layer with the given name. Sprite layers draw in the order of creation.
	Method CreateLayer:yimSpriteLayer(name:String)
		Return curState.sprWorld.AddLayer(name)
	End
	
	'summary: Creates a tile map on the current sprite layer using an array of strings containing pertinent map info.
	Method CreateTileMap:yimTileMap(mapInfo:String[])
		If mapInfo.Length = 6
			Return CreateTileMap(Int(mapInfo[0]), Int(mapInfo[1]), Int(mapInfo[2]), Int(mapInfo[3]), Float(mapInfo[4]), Float(mapInfo[5]))
		Else
			Local str:String = ""
			str.Join(mapInfo)
			LogMe("BAD MAP INFO: "+str)
			
			Return Null
		EndIf
	End
	
	'summary: Creates a tile map on the current sprite layer
	Method CreateTileMap:yimTileMap(tileWidth:Int, tileHeight:Int, numTilesX:Int, numTilesY:Int, xPos:Float=0.0, yPos:Float=0.0)
		Return curState.sprWorld.curLayer.AddTileMap(tileWidth, tileHeight, numTilesX, numTilesY, xPos, yPos)
	End
	
	'summary: Creates a collision group
	Method CreateCollGroup:yimCollGroup(name:String, collidesWithSelf:Bool)
		Local tGrp:yimCollGroup = New yimCollGroup(name, collidesWithSelf)
		collGroups.AddLast(tGrp)
		Return tGrp
	End
	
	'summary: Creates an event that is called on a certain interval
	Method CreateEvent:yimTicker(mills:Int, callback:yimTickerCallBack, autoStart:Bool=False)
		Local tTicker:yimTicker = New yimTicker(mills, autoStart, callback)
		events.AddLast(tTicker)
		Return tTicker
	End
	
	'summary: Creates an empty yimPath object
	Method CreatePath:yimPath()
		Local tPath:yimPath = New yimPath()
		paths.AddLast(tPath)
		Return tPath
	End
	
	Method LinkInputManager(im:yimputManager)
		inputManager = im
	End
	
	'summary: Creates an instance of a sprite that uses the same image object. Useful for creating multiple sprites without the slow down of repeatedly loading the image.
	Method CloneSprite:yimSprite(spr:yimSprite, withAnim:Bool=False)
		Local tSpr:yimSprite = New yimSprite(curState.sprWorld.curLayer, "")
		
		tSpr.img = spr.img
		tSpr.numFrames = spr.numFrames
		
		If withAnim
			tSpr.anims = spr.anims
			tSpr.curAnim = tSpr.curAnim
		EndIf
		
		curState.sprWorld.AddSprite(tSpr)
		
		Return tSpr
	End
	
	'summary: Loads the provided image file and creates a sprite out of it
	Method LoadSprite:yimSprite(file:String)
		Local tSpr:yimSprite = New yimSprite(curState.sprWorld.curLayer, file)
		curState.sprWorld.AddSprite(tSpr)
		
		Return tSpr
	End
	
	'summary: Loads the provided image file and creates a sprite sheet out of it
	Method LoadSpriteSheet:yimSprite(file:String, frameWidth:Int, frameHeight:Int, _numFrames:Int=1, animated:Bool=False)
	
		Local tSpr:yimSprite = New yimSprite(curState.sprWorld.curLayer, file, frameWidth, frameHeight, _numFrames)
		
		tSpr.SetAnimated(animated)
		curState.sprWorld.AddSprite(tSpr)
		
		Return tSpr
	
	End
	
	'summary: Removes the given sprite from the yimEngine
	Method RemoveSprite(spr:yimSprite)
		curState.sprWorld.RemoveSprite(spr)
	End
	
	'summary: Adds the removal of the sprite to a queue to prevent slowdown when deleting large numbers of sprites during one update
	Method DelayedRemoveSprite(spr:yimSprite)
		If Not curState.sprWorld.delayedDelList.Contains(spr)
			curState.sprWorld.delayedDelList.AddLast(spr)
		EndIf
	End
	
	'summary: Adds the provided particle emitter to the yimEngine
	Method AddParticleEmitter(emit:yimParticleEmitter)
		If curState.sprWorld.curLayer.sprList.Count() < 3000
			curState.sprWorld.partEmits.AddLast(emit)
		EndIf
	End
	
	Method PercentXtoY:Float(percX:Float)
		Return percX*(vPosMulti.x/vPosMulti.y)
	End
	
	Method PercentYtoX:Float(percY:Float)
		Return percY*(vPosMulti.y/vPosMulti.x)
	End
	
	Method ToPercentX:Float(pixelX:Float)
		Return pixelX/vPosMulti.x
	End
	
	Method ToPercentY:Float(pixelY:Float)
		Return pixelY/vPosMulti.y
	End
	
	Method ToPixelX:Float(percX:Float)
		Return percX*vPosMulti.x
	End
	
	Method ToPixelY:Float(percY:Float)
		Return percY*vPosMulti.y
	End
	
	'summary: Returns the x position of the mouse pointer on the map, as opposed to the screen
	Method MapMouseX:Float()
		Return curState.sprWorld.mapMouse.x
	End
	
	'summary: Returns the y position of the mouse pointer on the map, as opposed to the screen
	Method MapMouseY:Float()
		Return curState.sprWorld.mapMouse.y
	End
	
	'summary: Converts the given screen x and y coordinates to the map's x coordinate. Requires both x and y because of rotational calculations
	Method ScreenToMapX:Float(x:Float, y:Float)
		Return curState.sprWorld.camPos.x + (Cos(-curState.sprWorld.camAng)*(x - halfDevice.x) + Sin(-curState.sprWorld.camAng)*(y - halfDevice.y))/curState.sprWorld.vScale.x
	End
	
	'summary: Converts the given screen x and y coordinates to the map's y coordinate. Requires both x and y because of rotational calculations
	Method ScreenToMapY:Float(x:Float, y:Float)
		Return curState.sprWorld.camPos.y + (Sin(-curState.sprWorld.camAng)*(x - halfDevice.x) - Cos(-curState.sprWorld.camAng)*(y - halfDevice.y))/curState.sprWorld.vScale.y
	End
	
	'summary: Converts the given screen x and y coordinates to the map's x and y coordinates. You can pass an outVec to it to prevent creation of new yimVec2D object
	Method ScreenToMapPoint:yimVec2D(x:Float, y:Float, outVec:yimVec2D=Null)
		If outVec
			outVec.Set(ScreenToMapX(x, y), ScreenToMapY(x, y))
			Return Null
		Else
			Return New yimVec2D(ScreenToMapX(x, y), ScreenToMapY(x, y))
		EndIf
	End
	
	'summary: Converts the given map x and y coordinates to the screen's x coordinate.
	Method MapToScreenX:Float(x:Float, y:Float)
		Return halfDevice.x + (Cos(-curState.sprWorld.camAng)*(x - curState.sprWorld.camPos.x) + Sin(-curState.sprWorld.camAng)*(y - curState.sprWorld.camPos.y))*curState.sprWorld.vScale.x
	End
	
	'summary: Converts the given map x and y coordinates to the screen's y coordinate.
	Method MapToScreenY:Float(x:Float, y:Float)
		Return halfDevice.y + (Sin(-curState.sprWorld.camAng)*(x - curState.sprWorld.camPos.x) - Cos(-curState.sprWorld.camAng)*(y - curState.sprWorld.camPos.y))*curState.sprWorld.vScale.y
	End
	
	'summary: Converts the given map x and y coordinates to the screen's x and y coordinates.
	Method MapToScreenPoint:yimVec2D(x:Float, y:Float)
		Return New yimVec2D(MapToScreenX(x, y), MapToScreenY(x, y))
	End
	
	'summary: Returns the Millisec count of the current state. It is recommended that you use this (yE.Millisecs()) instead of Monkey's Millisecs() function, because of state pausing
	Method Millisecs:Int()
		Return curState.Milli()
	End
	
	' **** PHYSICS COMMANDS ****
	'
	'
	
	'summary: Creates a Revolute Joint
	Method PhysCreateRevoluteJoint:yimBox2DJoint(body1:yimBox2DBody, body2:yimBox2DBody=Null)
		If curState.sprWorld.b2dWorld
			Local w:yimBox2DWorld = curState.sprWorld.b2dWorld
			
			Return w.CreateRevoluteJoint(body1, body2)
		EndIf
	End
	
	'summary: Deletes the provided joint
	Method PhysDeleteJoint(joint:yimBox2DJoint)
		If curState.sprWorld.b2dWorld
			Local w:yimBox2DWorld = curState.sprWorld.b2dWorld
			
			w.DeleteJoint(joint)
		EndIf	
	End
	
	'summary: Creates a body with no shape
	Method PhysCreateBody:yimBox2DBody(x:Float, y:Float, isStatic:Bool=False)
		If curState.sprWorld.b2dWorld
			Local w:yimBox2DWorld = curState.sprWorld.b2dWorld
			Return w.CreateBody(x, y, isStatic)
		EndIf
	End
	
	'summary: Creates an edge body and adds it to the provided body
	Method PhysAddEdgeToBody(body:yimBox2DBody, x1:Float, y1:Float, x2:Float, y2:Float, density:Float=1.0, friction:Float=0.5, restitution:Float=0.1)
		If curState.sprWorld.b2dWorld
			Local w:yimBox2DWorld = curState.sprWorld.b2dWorld
			
			body.CreateFixture(w.CreateEdgeFixture(x1, y1, x2, y2, density, friction, restitution))
		EndIf
	End
	
	'summary: Creates a circle body and adds it to the provided body
	Method PhysAddCircleToBody(body:yimBox2DBody, x:Float, y:Float, radius:Float, density:Float=1.0, friction:Float=0.5, restitution:Float=0.1)
		If curState.sprWorld.b2dWorld
			Local w:yimBox2DWorld = curState.sprWorld.b2dWorld
			
			body.CreateFixture(w.CreateCircleFixture(radius, density, friction, restitution, x, y))
		EndIf
	End
	
	'summary: Creates a box body and adds it to the provided body
	Method PhysAddBoxToBody(body:yimBox2DBody, x:Float, y:Float, width:Float, height:Float, density:Float=1.0, friction:Float=0.5, restitution:Float=0.1)
		If curState.sprWorld.b2dWorld
			Local w:yimBox2DWorld = curState.sprWorld.b2dWorld
			
			body.CreateFixture(w.CreateBoxFixture(width, height, density, friction, restitution, x, y))
		EndIf
	End
	
	'summary: Links two bodies together
	Method PhysAddBodyToBody(bodyParent:yimBox2DBody, bodyChild:yimBox2DBody)
		If curState.sprWorld.b2dWorld
			Local w:yimBox2DWorld = curState.sprWorld.b2dWorld
			
			Local curFix:b2Fixture = bodyChild.GetFixtureList()
		
			While curFix
				bodyParent.CreateFixture(curFix.Copy())
				curFix = curFix.GetNext()
			Wend
			
			w.DeleteBody(bodyChild)
		EndIf
	End
	
	'summary: Gets the position of the physics body
	Method PhysGetBodyPosition:yimVec2D(body:yimBox2DBody)
		Local ret:yimVec2D = New yimVec2D(body.GetPosition().x*curState.sprWorld.b2dWorld.physScale, body.GetPosition().y*curState.sprWorld.b2dWorld.physScale)
		Return ret
	End
End
